package org.example.liuy.service.session;

import lombok.extern.slf4j.Slf4j;
import org.example.liuy.service.MonitoringService;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 智能限流会话管理器 - 保证10分钟内返回相同的session key
 * 优化并发性能版本
 */
@Slf4j
public class IntelligentSessionManager {

    // Session有效期（10分钟）
    private static final long SESSION_TTL = 10 * 60 * 1000L;

    // 时间窗口大小（10分钟），确保相同客户在10分钟内获得相同session key
    private static final long TIME_WINDOW = 10 * 60 * 1000L;
    private static final long TIME_TOLERANCE = 1000L; // 1秒的时间容忍度
    // 限流配置
    private static final int MAX_CONCURRENT_SESSIONS = 10000;
    private static final int MAX_SESSIONS_PER_SECOND = 50000;

    // 用于HMAC签名的密钥
    private static final String SECRET_KEY = "intelligent-session-secret-key";

    private final MonitoringService monitoringService;
    private final Mac mac;

    // 限流器
    private final Semaphore concurrentLimiter;
    private final RateLimiter rateLimiter;

    // 统计信息
    private final AtomicLong totalSessionsRequested = new AtomicLong(0);
    private final AtomicLong totalSessionsCreated = new AtomicLong(0);
    private final AtomicLong rejectedSessions = new AtomicLong(0);
    private final AtomicLong totalValidations = new AtomicLong(0);
    private final AtomicInteger currentConcurrentRequests = new AtomicInteger(0);

    // 字符集，只包含数字和字母
    private static final String ALPHANUMERIC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    // SessionKey长度，可以调整
    private static final int SESSION_KEY_LENGTH = 10;

    // 性能优化：预计算字符索引映射
    private static final int[] CHAR_INDEX_MAP = new int[128];

    // 静态初始化字符索引映射
    static {
        // 初始化映射数组
        for (int i = 0; i < CHAR_INDEX_MAP.length; i++) {
            CHAR_INDEX_MAP[i] = -1;
        }

        // A-Z 映射到 0-25
        for (int i = 0; i < 26; i++) {
            CHAR_INDEX_MAP['A' + i] = i;
        }

        // a-z 映射到 26-51
        for (int i = 0; i < 26; i++) {
            CHAR_INDEX_MAP['a' + i] = i + 26;
        }

        // 0-9 映射到 52-61
        for (int i = 0; i < 10; i++) {
            CHAR_INDEX_MAP['0' + i] = i + 52;
        }
    }

    public IntelligentSessionManager(MonitoringService monitoringService) {
        this.monitoringService = monitoringService;
        try {
            this.mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_KEY.getBytes(), "HmacSHA256");
            this.mac.init(secretKeySpec);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to initialize HMAC", e);
        }

        this.concurrentLimiter = new Semaphore(MAX_CONCURRENT_SESSIONS);
        this.rateLimiter = new RateLimiter(MAX_SESSIONS_PER_SECOND);
    }

    /**
     * 创建会话 - 保证10分钟内相同客户获得相同session key
     * @param customerId 客户ID
     * @return session键
     */
    public String createSession(Integer customerId) {
        totalSessionsRequested.incrementAndGet();

        // 性能优化：减少监控开销，只在采样时记录
        boolean shouldMonitor = totalSessionsRequested.get() % 1000 == 0;

        try {
            // 1. 检查速率限制
            if (!rateLimiter.tryAcquire()) {
                rejectedSessions.incrementAndGet();
                if (shouldMonitor) {
                    log.warn("Rate limit exceeded for session creation, customer: {}", customerId);
                }
                return generateRejectionResponse("RATE_LIMIT_EXCEEDED");
            }

            // 2. 检查并发限制
            if (!concurrentLimiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
                rejectedSessions.incrementAndGet();
                if (shouldMonitor) {
                    log.warn("Concurrent limit exceeded for session creation, customer: {}", customerId);
                }
                return generateRejectionResponse("CONCURRENT_LIMIT_EXCEEDED");
            }

            // 3. 增加当前并发请求数
            currentConcurrentRequests.incrementAndGet();

            try {
                // 4. 执行会话创建
                String sessionKey = doCreateSession(customerId);
                totalSessionsCreated.incrementAndGet();

                if (shouldMonitor) {
                    log.debug("Session created for customer: {}", customerId);
                }

                return sessionKey;
            } finally {
                // 5. 释放资源
                concurrentLimiter.release();
                currentConcurrentRequests.decrementAndGet();
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            rejectedSessions.incrementAndGet();
            return generateRejectionResponse("TIMEOUT");
        } catch (Exception e) {
            rejectedSessions.incrementAndGet();
            if (shouldMonitor) {
                log.error("Error creating session for customer: {}", customerId, e);
            }
            return generateRejectionResponse("INTERNAL_ERROR");
        }
    }

    /**
     * 实际执行会话创建 - 保证10分钟内相同客户获得相同session key
     */
    private String doCreateSession(Integer customerId) {
        long currentTime = getCurrentTime();
        // 使用floorDiv确保时间窗口对齐的一致性
        long alignedTime = Math.floorDiv(currentTime, TIME_WINDOW) * TIME_WINDOW;

        log.debug("Creating session - Customer: {}, CurrentTime: {}, AlignedTime: {}",
                customerId, currentTime, alignedTime);

        // 生成确定性的session key，嵌入customerId和时间信息
        return generateDeterministicSessionKey(customerId, alignedTime);
    }

    /**
     * 验证时间窗口 - 高性能版本
     * 只验证时间有效性，不重新生成session key
     */
    private boolean validateTimeWindow(String sessionKey, Integer customerId) {
        long currentTime = getCurrentTime();

        // 提取时间信息（第3-4位字符）
        int timePart1 = getIndexFromChar(sessionKey.charAt(2));
        int timePart2 = getIndexFromChar(sessionKey.charAt(3));
        int extractedTimeLow = (timePart2 << 6) | timePart1;

        log.debug("Validating session - Customer: {}, CurrentTime: {}, ExtractedTimeLow: {}",
                customerId, currentTime, extractedTimeLow);

        // 尝试不同的时间窗口（扩展到3个窗口以增加容错性）
        for (int i = 0; i < 3; i++) {
            long windowTime = Math.floorDiv(currentTime - i * TIME_WINDOW, TIME_WINDOW) * TIME_WINDOW;
            int windowTimeLow = (int) (windowTime & 0xFFF);

            log.debug("Checking window {} - WindowTime: {}, WindowTimeLow: {}", i, windowTime, windowTimeLow);

            if (windowTimeLow == extractedTimeLow) {
                // 验证时间是否在有效期内（增加容忍时间）
                long timeDiff = Math.abs(currentTime - windowTime);
                boolean isValid = timeDiff <= (SESSION_TTL + TIME_TOLERANCE);

                log.debug("Time window match - TimeDiff: {}, IsValid: {}", timeDiff, isValid);
                return isValid;
            }
        }

        log.debug("No matching time window found for session validation");
        return false;
    }

    private static long getCurrentTime() {
        return System.nanoTime() / 1_000_000; // 转换为毫秒
    }
    /**
     * 生成确定性的session key - 相同输入总是产生相同输出
     * 在session key中嵌入客户ID信息
     */
    private String generateDeterministicSessionKey(Integer customerId, long alignedTime) {
        // 使用customerId和时间生成哈希用于填充
        // 使用customerId和时间生成哈希用于填充
        String hashData = customerId + ":" + alignedTime + ":" + SECRET_KEY;
        byte[] hash = mac.doFinal(hashData.getBytes());

        // 构造session key字符数组
        char[] sessionKeyChars = new char[SESSION_KEY_LENGTH];

        // 第1-2位：客户ID的低12位转换为2个字符
        int customerIdLow = customerId & 0xFFF; // 取低12位
        sessionKeyChars[0] = getCharFromIndex(customerIdLow & 0x3F); // 低6位
        sessionKeyChars[1] = getCharFromIndex((customerIdLow >> 6) & 0x3F); // 高6位

        // 第3-4位：时间戳的部分信息
        int timeLow = (int) (alignedTime & 0xFFF); // 取时间戳低12位
        sessionKeyChars[2] = getCharFromIndex(timeLow & 0x3F); // 低6位
        sessionKeyChars[3] = getCharFromIndex((timeLow >> 6) & 0x3F); // 高6位

        // 剩余位置：使用哈希值确保唯一性和安全性
        int remainingLength = SESSION_KEY_LENGTH - 4;
        for (int i = 0; i < remainingLength && i < hash.length; i++) {
            int hashVal = Math.abs(hash[i]) % 62;
            sessionKeyChars[4 + i] = getCharFromIndex(hashVal);
        }

        // 如果哈希值不够填充剩余位置，使用随机字符填充
        if (remainingLength > hash.length) {
            ThreadLocalRandom random = ThreadLocalRandom.current();
            for (int i = hash.length; i < remainingLength; i++) {
                sessionKeyChars[4 + i] = getCharFromIndex(random.nextInt(62));
            }
        }

        return new String(sessionKeyChars);
    }

    /**
     * 根据索引获取字符（0-61映射到A-Z,a-z,0-9）
     */
    private char getCharFromIndex(int index) {
        index = index % 62;
        if (index < 26) {
            return (char) ('A' + index); // A-Z
        } else if (index < 52) {
            return (char) ('a' + index - 26); // a-z
        } else {
            return (char) ('0' + index - 52); // 0-9
        }
    }

    /**
     * 根据字符获取索引 - 高性能版本
     */
    private int getIndexFromChar(char c) {
        // 使用预计算的映射数组提高性能
        if (c < CHAR_INDEX_MAP.length) {
            int index = CHAR_INDEX_MAP[c];
            if (index != -1) {
                return index;
            }
        }
        return 0; // 默认返回0
    }

    /**
     * 验证会话 - 确保session key在10分钟内有效
     * 优化版本，提高并发性能
     */
    public SessionValidationResult validateSession(String sessionKey, Integer customerId) {
        // 减少监控开销
        boolean shouldMonitor = totalValidations.incrementAndGet() % 1000 == 0;

        try {
            // 快速参数检查
            if (sessionKey == null || customerId == null) {
                return SessionValidationResult.invalid("INVALID_PARAMETERS");
            }

            // 检查session key长度
            if (sessionKey.length() != SESSION_KEY_LENGTH) {
                return SessionValidationResult.invalid("INVALID_FORMAT");
            }

            // 快速字符验证（使用位运算优化）
            for (int i = 0; i < sessionKey.length(); i++) {
                char c = sessionKey.charAt(i);
                if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))) {
                    return SessionValidationResult.invalid("INVALID_CHARACTERS");
                }
            }

            // 直接提取并验证客户ID（避免重复生成session key）
            int extractedCustomerId = extractCustomerIdDirectly(sessionKey);
            if (extractedCustomerId != customerId) {
                return SessionValidationResult.invalid("CUSTOMER_ID_MISMATCH");
            }

            // 验证时间有效性（优化版本）
            if (!validateTimeWindow(sessionKey, customerId)) {
                return SessionValidationResult.invalid("SESSION_EXPIRED");
            }

            return SessionValidationResult.valid();

        } catch (Exception e) {
            if (shouldMonitor) {
                log.debug("Session validation failed for customer: {}", customerId, e);
            }
            return SessionValidationResult.invalid("VALIDATION_ERROR");
        }
    }

    /**
     * 直接从session key中提取客户ID - 高性能版本
     * 避免重新生成session key进行验证
     */
    private int extractCustomerIdDirectly(String sessionKey) {
        // 从session key的前两位提取客户ID信息
        int part1 = getIndexFromChar(sessionKey.charAt(0));  // 低6位
        int part2 = getIndexFromChar(sessionKey.charAt(1));  // 高6位

        return (part2 << 6) | part1;
    }


    /**
     * 从session key中提取客户ID - 高性能版本
     */
    public Integer getCustomerIdFromSession(String sessionKey) {
        // 快速参数检查
        if (sessionKey == null || sessionKey.length() != SESSION_KEY_LENGTH) {
            return null;
        }

        // 快速字符验证
        for (int i = 0; i < sessionKey.length(); i++) {
            char c = sessionKey.charAt(i);
            if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))) {
                return null;
            }
        }

        try {
            // 直接提取客户ID
            return extractCustomerIdDirectly(sessionKey);
        } catch (Exception e) {
            log.debug("Failed to extract customer ID from session key: {}", sessionKey, e);
            return null;
        }
    }

    /**
     * 生成拒绝响应 - 也只包含数字和字母
     */
    private String generateRejectionResponse(String reason) {
        // 生成随机的拒绝响应，看起来像正常的session key
        StringBuilder sb = new StringBuilder(SESSION_KEY_LENGTH);
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0; i < SESSION_KEY_LENGTH; i++) {
            sb.append(ALPHANUMERIC.charAt(random.nextInt(ALPHANUMERIC.length())));
        }
        return sb.toString();
    }

    /**
     * 获取系统状态
     */
    public SystemStatus getSystemStatus() {
        return new SystemStatus(
                totalSessionsRequested.get(),
                totalSessionsCreated.get(),
                rejectedSessions.get(),
                totalValidations.get(),
                currentConcurrentRequests.get(),
                rateLimiter.getAvailablePermits()
        );
    }

    public void startCleanupTask() {
        log.info("Intelligent session manager started with limits: {} concurrent, {} sessions/sec",
                MAX_CONCURRENT_SESSIONS, MAX_SESSIONS_PER_SECOND);
    }

    public void stop() {
        log.info("Intelligent session manager stopped. Stats: {}", getStatistics());
    }

    public String getStatistics() {
        SystemStatus status = getSystemStatus();
        long totalRequested = status.getTotalSessionsRequested();
        double rejectionRate = totalRequested > 0 ?
                (double) status.getRejectedSessions() / totalRequested * 100 : 0;

        return String.format(
                "Sessions - Requested: %d, Created: %d, Rejected: %d (%.2f%%), " +
                        "Validations: %d, Current: %d",
                status.getTotalSessionsRequested(), status.getTotalSessionsCreated(),
                status.getRejectedSessions(), rejectionRate,
                status.getTotalValidations(), status.getCurrentConcurrentRequests());
    }

    /**
     * 会话验证结果
     */
    public static class SessionValidationResult {
        private final boolean valid;
        private final String reason;

        private SessionValidationResult(boolean valid, String reason) {
            this.valid = valid;
            this.reason = reason;
        }

        public static SessionValidationResult valid() {
            return new SessionValidationResult(true, null);
        }

        public static SessionValidationResult invalid(String reason) {
            return new SessionValidationResult(false, reason);
        }

        public boolean isValid() { return valid; }
        public String getReason() { return reason; }
    }

    /**
     * 系统状态
     */
    public static class SystemStatus {
        private final long totalSessionsRequested;
        private final long totalSessionsCreated;
        private final long rejectedSessions;
        private final long totalValidations;
        private final int currentConcurrentRequests;
        private final int availableRateLimitPermits;

        public SystemStatus(long totalSessionsRequested, long totalSessionsCreated,
                            long rejectedSessions, long totalValidations,
                            int currentConcurrentRequests, int availableRateLimitPermits) {
            this.totalSessionsRequested = totalSessionsRequested;
            this.totalSessionsCreated = totalSessionsCreated;
            this.rejectedSessions = rejectedSessions;
            this.totalValidations = totalValidations;
            this.currentConcurrentRequests = currentConcurrentRequests;
            this.availableRateLimitPermits = availableRateLimitPermits;
        }

        // Getters
        public long getTotalSessionsRequested() { return totalSessionsRequested; }
        public long getTotalSessionsCreated() { return totalSessionsCreated; }
        public long getRejectedSessions() { return rejectedSessions; }
        public long getTotalValidations() { return totalValidations; }
        public int getCurrentConcurrentRequests() { return currentConcurrentRequests; }
        public int getAvailableRateLimitPermits() { return availableRateLimitPermits; }
    }

    /**
     * 简单的速率限制器
     */
    private static class RateLimiter {
        private final int maxPermitsPerSecond;
        private final AtomicLong lastRefillTime = new AtomicLong(System.currentTimeMillis());
        private final AtomicInteger availablePermits;

        public RateLimiter(int maxPermitsPerSecond) {
            this.maxPermitsPerSecond = maxPermitsPerSecond;
            this.availablePermits = new AtomicInteger(maxPermitsPerSecond);
        }

        public boolean tryAcquire() {
            refill();
            return availablePermits.getAndDecrement() > 0;
        }

        private void refill() {
            long now = System.currentTimeMillis();
            long lastRefill = lastRefillTime.get();

            if (now - lastRefill >= 1000) {
                if (lastRefillTime.compareAndSet(lastRefill, now)) {
                    availablePermits.set(maxPermitsPerSecond);
                }
            }
        }

        public int getAvailablePermits() {
            refill();
            return Math.max(0, availablePermits.get());
        }
    }
}
